﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using GSMS.Models;
using GSMS.Properties;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GsmComm.GsmCommunication;
using GsmComm.PduConverter;

namespace GSMS.ViewModel
{
    public class GsmsViewModel : ViewModelBase
    {
        #region Fields & Constants

        private GsmCommMain comm;

        #endregion

        public GsmsViewModel()
        {
            // Initialize commands
            this.CommandSend = new RelayCommand(CommandSendExecute);
            this.CommandClear = new RelayCommand(CommandClearExecute);

            // Initialize list of COM ports
            var portList = new ObservableCollection<ComPortModel>();
            for (int i = 1; i <= 9; i++)
                portList.Add(new ComPortModel(i));
            this.ComPortList = portList;

            // Load default settings
            this.ReloadSettings();
        }

        #region Properties

        private string message;
        public string Message
        {
            get { return message; }
            set { message = value; RaisePropertyChanged("Message"); }
        }
        
        private string phoneNumber;
        public string PhoneNumber
        {
            get { return phoneNumber; }
            set { phoneNumber = value; RaisePropertyChanged("PhoneNumber"); }
        }
        
        private ComPortModel comPort;
        public ComPortModel ComPort
        {
            get { return comPort; }
            set { comPort = value;  RaisePropertyChanged("ComPort"); }
        }

        private ObservableCollection<ComPortModel> comPortList;
        public ObservableCollection<ComPortModel> ComPortList
        {
            get { return comPortList; }
            set { comPortList = value; RaisePropertyChanged("ComPortList"); }
        }

        #endregion

        #region Commands

        private RelayCommand commandSend;
        public RelayCommand CommandSend
        {
            get { return commandSend; }
            set { commandSend = value; RaisePropertyChanged("CommandSend"); }
        }

        private RelayCommand commandClear;
        public RelayCommand CommandClear
        {
            get { return commandClear; }
            set { commandClear = value; RaisePropertyChanged("CommandClear"); }
        }
        
        #endregion

        #region Private Methods

        private void CommandSendExecute()
        {
            if (!isValidMessage(Message))
                return;
            if (!isValidPhone(PhoneNumber))
                return;
            if (!isValidPort(ComPort.Id))
                return;

            int successCount = 0;
            int messageCount = 0;

            using (StringReader sr = new StringReader(Message))
            {
                string curLine;

                while ((curLine = sr.ReadLine()) != null)
                {
                    string msgToSend = curLine.Trim();
                    if (!String.IsNullOrWhiteSpace(msgToSend)) // Only count/send non-empty lines
                    {
                        messageCount++;
                        if (SendMessage(msgToSend, phoneNumber))
                            successCount++;
                    }

                }

                // Close the connection and release port
                comm.Close();
            }
            
            MessageBox.Show(successCount + "/" + messageCount + " message(s) sent successfully!");
            this.CommandClearExecute();
        }

        private void CommandClearExecute()
        {
            Message = string.Empty;
        }

        private void ReloadSettings()
        {
            // Default phone
            string defPhone = Settings.Default.DefaultPhone;
            if (!String.IsNullOrWhiteSpace(defPhone))
                PhoneNumber = defPhone;

            // Default port
            int defPort = Settings.Default.DefaultPort;
            if (defPort > 0 && defPort < 10)
                ComPort = ComPortList.Where(port => port.Id == defPort).FirstOrDefault();
        }

        private bool SendMessage(string msgToSend, string destination)
        {
            SmsSubmitPdu pdu = new SmsSubmitPdu(msgToSend, destination);
            comm.SendMessage(pdu);
            return true;
        }

        private bool isValidMessage(string messageToValidate)
        {
            if (String.IsNullOrWhiteSpace(messageToValidate))
            {
                MessageBox.Show("Error! Message cannot be empty!");
                return false;
            }
            return true;
        }

        private bool isValidPhone(string phoneString)
        {
            if (String.IsNullOrWhiteSpace(phoneString) || !phoneString.All(Char.IsNumber))
            {
                MessageBox.Show("Error! Invalid phone number!");
                return false;
            }
            return true;
        }

        private bool isValidPort(int port)
        {
            // Check GSM port
            comm = new GsmCommMain(port);

            try
            {
                comm.Open();

                const int retries = 20;
                int i = 0;
                while (!comm.IsConnected())
                {
                    i++;
                    if (i > retries)
                    {
                        MessageBox.Show("Error! No GSM Modem detect on COM" + comPort);
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error! " + ex.Message);
                return false;
            }

            return true;
        }
        
        #endregion
    }
}
